package com.itc.bpm.framework.service.impl;



import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itc.bi.api.BiService;
import com.itc.bi.api.constant.SystemConstant;
import com.itc.bi.api.dto.DataSetDto;
import com.itc.bi.api.dto.ParamsDto;
import com.itc.bi.api.vo.DataSetVO;
import com.itc.bpm.api.util.io.IoUtils;
import com.itc.bpm.bean.BpmModel;
import com.itc.bpm.bean.BpmProcessInstanceExt;
import com.itc.bpm.dto.ParamsItemDto;
import com.itc.bpm.dto.ProcessParamsDto;
import com.itc.bpm.framework.factory.BpmProcessDefinitionService;
import com.itc.bpm.framework.factory.BpmServiceFactory;
import com.itc.bpm.framework.factory.vo.BpmStartVO;
import com.itc.bpm.framework.service.ProcessInstanceService;
import com.itc.bpm.service.BpmModelService;
import com.itc.bpm.service.BpmProcessInstanceExtService;
import com.itc.bpm.service.BpmProcessTaskExtService;
import com.itc.bpm.util.JsonUtils;
import com.itc.common.core.domain.R;
import com.itc.common.core.utils.StringUtils;

import com.itc.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 *@title ProcessInstanceServiceImpl
 *@description
 *@author yl
 */
@Slf4j
@Service
public class ProcessInstanceServiceImpl extends BpmServiceFactory implements ProcessInstanceService {



    @Autowired
    @Lazy
    BpmProcessDefinitionService processDefinitionService;

    @Autowired
    @Lazy
    BpmModelService bpmModelService;

    @Autowired
    @Lazy
    BpmProcessInstanceExtService bpmProcessInstanceExtService;

    @Autowired
    @Lazy
    BpmProcessTaskExtService bpmProcessTaskExtService;

    @Lazy
    @Autowired(required = false)
    BiService biService;

    @Override
    public R createProcessInstance(String processKey, Map<String, Object> params, String businessKey) {
        return null;
    }

    @Override
    public String createProcessInstance2(String processKey, Map<String, Object> params, String businessKey) {
        return null;
    }

    @Override
    public void delete(String processKey) {

    }

    @Override
    public void updateProcessInstanceState(Integer state, String instanceId) {

    }

    @Override
    public void delete(String instanceId, String deleteReason) {

    }

    @Transactional
    @Override
    public R<String> createProcessInstance(BpmStartVO bpmStartVO) {
        if(StringUtils.isEmpty(bpmStartVO.getModelId())){
            return R.fail("流程模型id不能为空");
        }
        // 校验当前业务是否已经发起流程，不可重复发起操作

        String[] modelIds = bpmStartVO.getModelId().split(",");
        for(String modelId:modelIds){
            Boolean flag =  bpmProcessInstanceExtService.checkServiceIsExists(bpmStartVO.getBusinessKey(),modelId);
            if(!flag){
                return R.fail("当前业务已发起流程，不可重复发起！");
            }
             BpmModel bpmModel = bpmModelService.getById(modelId);
             if(bpmModel==null){
                 return R.fail("流程模型不存在，请重新选择！");
             }
             if(StringUtils.isEmpty(bpmModel.getDeployId())){
                 return R.fail(bpmModel.getBpmName()+"流程模型未部署，请重新选择！");
             }
            Model model = repositoryService.createModelQuery().modelId(bpmModel.getDeployId()).latestVersion().singleResult();
            ProcessDefinition processDefinition =repositoryService.createProcessDefinitionQuery().deploymentId(model.getDeploymentId()).latestVersion().singleResult();
            if(processDefinition == null){
                return R.fail("流程定义不存在，请联系管理员确认后重新发起");
            }
            // 获取航班类型参数
            Map<String,Object> paramsMap = new HashMap<>();
            if(StringUtils.isNotEmpty(bpmModel.getConditionJson())){
                paramsMap = getBiParams(bpmModel.getConditionJson(),bpmStartVO.getBusinessKey());
            }
            InputStream processDefinitionXml = repositoryService.getProcessModel(processDefinition.getId());
            //String xml = IoUtils.readUtf8(processDefinitionXml,true);
            Map<String,Object> params = bpmStartVO.getData();
            if(params==null){
                params = new HashMap<>();
            }
            params.putAll(paramsMap);
            params.put("initiator", SecurityUtils.getUserId());
            params.put("businessKey", bpmStartVO.getBusinessKey());
            params.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
            params.put("modelId",bpmStartVO.getModelId());
            params.put("instanceName",model.getName());
            ProcessInstance instance = runtimeService.startProcessInstanceById(processDefinition.getId(), bpmStartVO.getBusinessKey().toString(), params);
            // 设置流程名字
           // runtimeService.setProcessInstanceName(instance.getId(), processDefinition.getName());
            BpmProcessInstanceExt processInstanceExt = new BpmProcessInstanceExt();
            processInstanceExt.setProcessInstanceId(instance.getId());
            processInstanceExt.setStatus(0);
            processInstanceExt.setResult(0);
            processInstanceExt.setName(processDefinition.getName());
            processInstanceExt.setServiceId(bpmStartVO.getBusinessKey()+"");
            processInstanceExt.setProcessDefinitionId(processDefinition.getId());
            processInstanceExt.setBpmKey(processDefinition.getKey());
            processInstanceExt.setVersion(processDefinition.getVersion()+".0");
            processInstanceExt.setFlightNumber(bpmStartVO.getFlightNumber());
            processInstanceExt.setStartUserId(SecurityUtils.getUserId()+"");
            processInstanceExt.setCreateBy(SecurityUtils.getUserId()+"");
            // 记录model 标记
            processInstanceExt.setCategory(bpmModel.getCategory());
            processInstanceExt.setIsPublicProcess(bpmModel.getIsPublicProcess());
            processInstanceExt.setIsImportantEvent(bpmModel.getIsImportantEvent());
            processInstanceExt.setBpmModelId(bpmModel.getId());
            processInstanceExt.setDescription(bpmModel.getDescription());
            bpmProcessInstanceExtService.save(processInstanceExt);
        }
        return R.ok("启动成功");
    }

    @Override
    public R cacenProcessInstance(String processInstaneId) {
        ProcessInstance instance =  runtimeService.createProcessInstanceQuery().processInstanceId(processInstaneId).singleResult();
        if (instance == null) {
            return R.fail("流程实例不存在，无法取消");
        }
        runtimeService.deleteProcessInstance(processInstaneId, "主动取消流程");
        //记录流程实例
        BpmProcessInstanceExt bpmProcessInstanceExt = bpmProcessInstanceExtService.getProcessInstanceExtByInstanceId(processInstaneId);
        bpmProcessInstanceExt.setStatus(2);
        bpmProcessInstanceExt.setEndTime(new Date());
        bpmProcessInstanceExtService.updateById(bpmProcessInstanceExt);
        // 终止进行中任务
        bpmProcessTaskExtService.cancenProcessTasks(processInstaneId);
        return R.ok();
    }

    @Override
    public String findProcessXmlData(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        if (bpmnModel == null) {
            return null;
        }
        BpmnXMLConverter converter = new BpmnXMLConverter();
        return StrUtil.utf8Str(converter.convertToXML(bpmnModel));
    }

    @Override
    public String createSignProcessInstance(BpmStartVO bpmStartVO) {
        String modelId = bpmStartVO.getModelId();
        BpmModel bpmModel = bpmModelService.getById(modelId);
        if(bpmModel==null){
            throw new RuntimeException("流程模型不存在");
        }
        if(StringUtils.isEmpty(bpmModel.getDeployId())){
            throw new RuntimeException(bpmModel.getBpmName()+"流程模型未部署，请重新选择！");
        }
        Model model = repositoryService.createModelQuery().modelId(bpmModel.getDeployId()).latestVersion().singleResult();
        ProcessDefinition processDefinition =repositoryService.createProcessDefinitionQuery().deploymentId(model.getDeploymentId()).latestVersion().singleResult();
        if(processDefinition == null){
            throw new RuntimeException("流程定义不存在，请联系管理员确认后重新发起");
        }
        Map<String,Object> params = bpmStartVO.getData();
        if(params==null){
            params = new HashMap<>();
        }
        params.put("initiator", SecurityUtils.getUserId());
        params.put("businessKey", bpmStartVO.getBusinessKey());
        params.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
        ProcessInstance instance = runtimeService.startProcessInstanceById(processDefinition.getId(), bpmStartVO.getBusinessKey().toString(), params);
        // 设置流程名字
        // runtimeService.setProcessInstanceName(instance.getId(), processDefinition.getName());
        BpmProcessInstanceExt processInstanceExt = new BpmProcessInstanceExt();
        processInstanceExt.setProcessInstanceId(instance.getId());
        processInstanceExt.setStatus(0);
        processInstanceExt.setResult(0);
        processInstanceExt.setName(processDefinition.getName());
        processInstanceExt.setServiceId(bpmStartVO.getBusinessKey()+"");
        processInstanceExt.setProcessDefinitionId(processDefinition.getId());
        processInstanceExt.setBpmKey(processDefinition.getKey());
        processInstanceExt.setCategory(processDefinition.getCategory());
        processInstanceExt.setVersion(processDefinition.getVersion()+".0");
        processInstanceExt.setFlightNumber(bpmStartVO.getFlightNumber());
        processInstanceExt.setStartUserId(SecurityUtils.getUserId()+"");
        processInstanceExt.setCreateBy(SecurityUtils.getUserId()+"");
        // 记录model 标记
        processInstanceExt.setIsPublicProcess(bpmModel.getIsPublicProcess());
        processInstanceExt.setIsImportantEvent(bpmModel.getIsImportantEvent());
        processInstanceExt.setBpmModelId(bpmModel.getId());
        bpmProcessInstanceExtService.save(processInstanceExt);
        return processInstanceExt.getProcessInstanceId();
    }

    @Override
    public R<String> cancelProcessByserviceId(String serviceId) {
        List<BpmProcessInstanceExt> list =  bpmProcessInstanceExtService.list(new LambdaQueryWrapper<BpmProcessInstanceExt>().eq(BpmProcessInstanceExt::getServiceId,serviceId).eq(BpmProcessInstanceExt::getStatus,0));
        for (BpmProcessInstanceExt item:list){
            String processInstaneId = item.getProcessInstanceId();
            ProcessInstance instance =  runtimeService.createProcessInstanceQuery().processInstanceId(processInstaneId).singleResult();
            if (instance == null) {
                continue;
                //return R.fail("流程实例不存在，无法取消");
            }
            runtimeService.deleteProcessInstance(processInstaneId, "飞机起飞，主动取消流程");
            //记录流程实例
            BpmProcessInstanceExt bpmProcessInstanceExt = bpmProcessInstanceExtService.getProcessInstanceExtByInstanceId(processInstaneId);
            bpmProcessInstanceExt.setStatus(2);
            bpmProcessInstanceExt.setEndTime(new Date());
            bpmProcessInstanceExtService.updateById(bpmProcessInstanceExt);
            // 终止进行中任务
            bpmProcessTaskExtService.cancenProcessTasks(processInstaneId);
        }
        return R.ok();
    }

    /**
     * 调用bi 服务获取数据
     * @param json
     * @param serviceId
     * @return
     */
    public Map<String,Object> getBiParams(String json,String serviceId){
        Map<String,Object> params = new HashMap<>();
        try {
            List<Map> processParamsDtos = JsonUtils.jsonToList(json, Map.class);
            Map<String,String> temp = new HashMap<>();
            if(CollectionUtils.isEmpty(processParamsDtos)){
                return params;
            }
            // 解析条件结构
            for(Map t:processParamsDtos){
                List<Map> list  = (List<Map>) t.get("list");
                if(CollectionUtils.isNotEmpty(list)){
                   for(Map d:list){
                       ParamsItemDto itemDto = new ParamsItemDto(d);
                       if(itemDto.getDataset()==null || itemDto.getDataset().equals("null")) continue;
                       String key = itemDto.getDataset()+":"+itemDto.getIdKey();
                       if(temp.containsKey(key)){
                           String itemRes = temp.get("key");
                           itemRes = itemRes+","+itemDto.getFieldKey();
                           temp.put(key,itemRes);
                       }else{
                           temp.put(key,itemDto.getFieldKey());
                       }
                   }
                }
            }
            // 组装bi 服务获取条件表达式参数值
            for(String key:temp.keySet()){
                DataSetDto dataSetDto = new DataSetDto();
                String[] arrs = key.split(":");
                dataSetDto.setDataSetId(Long.parseLong(arrs[0]));
                ParamsDto paramsDto = new ParamsDto();
                paramsDto.setColumnName(arrs[1]);
                paramsDto.setValue(serviceId);
                paramsDto.setType(SystemConstant.FILTER_CONDITION_EQ);
                List<ParamsDto> paramsDtoList = new ArrayList<>();
                paramsDtoList.add(paramsDto);
                dataSetDto.setParams(paramsDtoList);
                dataSetDto.setPageSize(1);
                dataSetDto.setPageIndex(1);
                String keyValue = temp.get(key);
                String[] fields = keyValue.split(",");
                Map<String,Object> tempparams = new HashMap<>();
                try {
                    R<DataSetVO> r = biService.queryDataSetData(dataSetDto);

                    if(r!=null){
                        DataSetVO data = r.getData();
                        List<LinkedHashMap<String, Object>> result = data.getData();
                        if(result.size()>0){
                            LinkedHashMap<String, Object> resultMap = result.get(0);
                            for(String fieldKey:fields){
                                String valueKey = "param_"+ arrs[0]+"_"+fieldKey;
                                if(resultMap.containsKey(fieldKey)){
                                    tempparams.put(valueKey,resultMap.get(fieldKey));
                                }else{
                                    tempparams.put(valueKey,"");
                                }
                            }
                        }
                    }

                }catch (Exception e){
                    e.printStackTrace();
                    log.error("调用BI 服务失败",e.getMessage());
                }
                log.info(arrs[0]+"--调用BI 组装参数",JsonUtils.objectToJson(tempparams));
                if(tempparams.isEmpty()){
                    for(String fieldKey:fields){
                        String valueKey = "param_"+arrs[0]+"_"+fieldKey;
                        tempparams.put(valueKey,"");
                    }
                }
                params.putAll(tempparams);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("--组装结果：--",JsonUtils.objectToJson(params));
        return params;
    }


}
